﻿namespace StockSharp.AlfaDirect
{
	using System;
	using System.Collections.Generic;
	using System.Text.RegularExpressions;

	using Ecng.Collections;
	using Ecng.Common;

	using StockSharp.BusinessEntities;

	/// <summary>
	/// Вспомагательный класс, который используется для доступа к специфичной AlfaDirect информации через <see cref="IExtendableEntity.ExtensionInfo"/>.
	/// </summary>
	public static class AlfaExtensions
	{
		private const string _securityKeyCurrency = "key_currency";
		private const string _securityKeyPaperNo = "paper_no";
		private const string _securityKeyPlaceCode = "place_code";
		private const string _orderAveragePrice = "avg_trd_price";

		/// <summary>
		/// Получить валюту для инструмента.
		/// </summary>
		/// <param name="security">Инструмент.</param>
		/// <returns>Валюта.</returns>
		public static string GetCurrency(this Security security)
		{
			return security.GetValue<string>(_securityKeyCurrency);
		}

		internal static void SetCurrency(this Security security, string currency)
		{
			security.AddValue(_securityKeyCurrency, currency);
		}

		/// <summary>
		/// Получить AlfaDirect-номер инструмента.
		/// </summary>
		/// <param name="security">Инструмент.</param>
		/// <returns>AlfaDirect-номер инструмента.</returns>
		public static int GetPaperNo(this Security security)
		{
			return security.GetValue<int>(_securityKeyPaperNo);
		}

		internal static void SetPaperNo(this Security security, int paperNo)
		{
			security.AddValue(_securityKeyPaperNo, paperNo);
		}

		/// <summary>
		/// Получить код площадки инструмента.
		/// </summary>
		/// <param name="security">Инструмент.</param>
		/// <returns>Код площадки.</returns>
		public static string GetPlaceCode(this Security security)
		{
			return security.GetValue<string>(_securityKeyPlaceCode);
		}

		internal static void SetPlaceCode(this Security security, string placeCode)
		{
			security.AddValue(_securityKeyPlaceCode, placeCode);
		}

		/// <summary>
		/// Получить среднюю цену исполнения.
		/// </summary>
		/// <param name="order">Заявка.</param>
		/// <returns>Средняя цену исполнения..</returns>
		public static decimal GetAlfaAveragePrice(this Order order)
		{
			return order.GetValue<decimal>(_orderAveragePrice);
		}

		/// <summary>
		/// Получить дополнительные поля по опционам: Страйк, Тип опциона, Базовый актив
		/// </summary>
		/// <remarks>
		/// http://stocksharp.com/forum/yaf_postsm21467_Optsiony-v-Al-fa-Diriekt.aspx#post21467
		/// </remarks>
		public static Security GetOptionInfo(this string security)
		{
			const string call = "ABCDEFGHIJKL";
			//const string put  = "MNOPQRSTUVWX";

			var regex = new Regex(@"^([A-z]{2})(\d+)([A-z])([A-z])(\d)\Z", RegexOptions.Compiled | RegexOptions.IgnoreCase);

			var matches = regex.Matches(security);

			if (matches.Count == 1)
			{
				var groups = matches[0].Groups;

				return new Security
				{
					Strike = groups[2].Value.To<decimal>(),
					OptionType = (call.Contains(groups[4].Value.ToUpper()) ? OptionTypes.Call : OptionTypes.Put),
					UnderlyingSecurityId = GetFutures(groups[1].Value.ToUpper(),
													   Convert.ToChar(groups[4].Value.ToUpper()) - 64,
													   groups[5].Value.To<int>())
				};
			}

			return null;
		}

		internal static void SetAlfaAveragePrice(this Order order, decimal price)
		{
			order.AddValue(_orderAveragePrice, price);
		}

		/// <remarks>
		/// http://stocksharp.com/forum/yaf_postsm21467_Optsiony-v-Al-fa-Diriekt.aspx#post21467
		/// </remarks>
		private static string GetFutures(string cod, int month, int year)
		{
			var underlyingSecurity = new Dictionary<string, string>
			{
				{ "GZ", "GAZP"   },
				{ "RI", "RTSI"   },
				{ "GM", "GMKR"   },
				{ "Si", "Si"     },
				{ "SR", "SBER"   },
				{ "VB", "VTBR"   },
				{ "RS", "RTSSTD" },
				{ "UR", "UR"     },
				{ "SV", "SILV"   },
				{ "PT", "PLT"    },
				{ "PD", "PLD"    },
				{ "Eu", "Eu"     },
				{ "ED", "ED"     },
				{ "BR", "BR"     },
				{ "AU", "AUDU"   },
			};

			if (month > 12) month -= 12;

			if (month <= 3)
				month = 3;
			else if (month <= 6)
				month = 6;
			else if (month <= 9)
				month = 9;
			else if (month <= 12)
				month = 12;

			try
			{
				return underlyingSecurity[cod] + "-" + month + "." + (year + 10) + "@FORTS";
			}
			catch
			{
				return null;
			}
		}

		private static void AddValue(this IExtendableEntity entity, string key, object value)
		{
			if (entity == null)
				throw new ArgumentNullException("entity");

			if (entity.ExtensionInfo == null)
				throw new ArgumentException("entity");

			entity.ExtensionInfo[key] = value;
		}

		private static T GetValue<T>(this IExtendableEntity entity, string key)
		{
			if (entity == null)
				throw new ArgumentNullException("entity");

			if (entity.ExtensionInfo == null)
				throw new ArgumentException("entity");

			return (T)entity.ExtensionInfo.TryGetValue(key);
		}

		internal static void RaisePropertyChanged(this IExtendableEntity entity)
		{
			if (entity == null)
				throw new ArgumentNullException("entity");

			entity.NotifyPropertyChanged("ExtensionInfo");
		}
	}
}